HUSKYLENS 2 实时图传教程
1. 什么是实时图传
实时图传可以将 HUSKYLENS 2 摄像头的画面传输到电脑,方便在更大的屏幕上查看,也可以在 Python 或 Mind+ 中使用图像。
HUSKYLENS 2 提供 WebRTC 和 RTSP 两种图传协议。首次使用,建议从 WebRTC + 浏览器开始:完成设备联网后,在浏览器中输入设备地址即可查看画面,无需编写程序或安装专门的播放器。
本教程先介绍联网与 IP 地址的准备,再介绍浏览器图传,最后介绍 Python、Mind+ 和 VLC 等其他实现方式。
在设备屏幕上查找“实时图传”功能。如果没有找到,请先按照HUSKYLENS 2 固件更新教程更新固件。
2. 实时图传准备
电脑通过 HUSKYLENS 2 的 IP 地址访问图传服务。你可以选择 USB 有线连接或 WiFi 无线连接,完成其中一种即可继续。
| 连接方式 | 需要准备 | 后续填写的 IP |
|---|---|---|
| USB 有线连接 | 支持数据传输的 Type-C 数据线;Windows 电脑需要识别 RNDIS 网络接口 | 设备屏幕显示的有线 IP,本文示例为 192.168.88.1 |
| WiFi 无线连接 | HUSKYLENS 2 WiFi 模块;设备和电脑连接到同一个可互通的 WiFi 网络 | 设备屏幕显示的无线 IP,本文示例为 192.168.9.181 |
2.1 有线图传准备
连接设备
使用 Type-C 数据线,将 HUSKYLENS 2 连接到电脑。
USB 有线图传通过网络连接传输画面。Windows 电脑需要正确识别设备的 RNDIS 网络接口,需要安装对应的RNDIS驱动。
安装 RNDIS 驱动
注:如果电脑已经能够识别设备的 RNDIS 网络接口,可以跳过驱动安装。
以下以 Windows 11 为例,结合图示完成安装:
- 右键点击 Windows 开始按钮,打开“设备管理器”。
- 找到连接 HUSKYLENS 2 后出现的未识别设备或 RNDIS 设备,右键选择“更新驱动程序”。
选择“浏览我的电脑以查找驱动程序”,再选择“让我从计算机上的可用驱动程序列表中选取”。
- 按照下方图示,在网络适配器相关选项中选择 RNDIS 兼容驱动,完成安装。不同系统显示名称可能有所不同。
- 安装完成后,确认设备出现在“网络适配器”列表中,且没有黄色警告标记。
如果按照图示仍无法安装,请根据系统版本联系技术支持。
驱动安装完成后,保持 USB 连接。后续开启图传并进入模型界面时,查看设备显示的有线 IP 地址。
如下,通过Type-C线连接电脑与Huskylens 2后有线IP地址固定为192.168.88.1。
2.2 无线图传准备
- 准备HUSKYLENS 2 WiFi 模块,在设备断电时按照模块说明安装,然后为设备供电。安装教程:点击查看。
- 在 HUSKYLENS 2 的设置中进入 WiFi 设置,选择电脑所连接的同一WiFi 名称,手动输入密码并连接。
- 确认设备连接成功,并确认电脑也连接到同一个 WiFi。该网络需要允许电脑与设备相互访问。
- 后续开启图传并进入模型界面时,查看设备显示的无线 IP 地址,记录下来。
重新连接 WiFi 后,设备 IP 可能变化,请以设备当前显示的地址为准。如果屏幕同时显示有线和无线 IP,请选择与你当前连接方式对应的地址。
3. 使用 WebRTC 在浏览器中查看实时画面
完成第 2 节中的任意一种连接方式后,按下面的步骤操作。有线和无线的浏览器操作相同,只需填写对应的设备 IP。
3.1 开启 WebRTC 图传
- 在 HUSKYLENS 2 中进入“实时图传”。
- 打开 WebRTC 图传开关,点击确认。
- 设备返回主界面,右上角显示实时图传图标。
- 打开一个模型,例如“人脸识别”,查看屏幕显示的 IP 地址。第一行为有线IP地址。第2行为无线IP地址。
3.2 输入地址并播放画面
在电脑浏览器的地址栏输入对应地址,按回车打开页面:
| 当前连接方式 | 浏览器地址示例 | 如何填写 |
|---|---|---|
| USB 有线 | http://192.168.88.1 | 使用设备显示的有线 IP |
| WiFi 无线 | http://192.168.9.231 | 将示例 IP 替换为设备显示的无线 IP |
地址格式为 http://设备IP。进入页面后,点击 play stream,即可查看实时画面。
如果页面无法打开,先检查 IP 是否填写正确:有线连接检查数据线和 RNDIS 网络接口;无线连接检查设备与电脑是否已连接同一个可互通的 WiFi。页面能打开但没有画面时,检查设备是否已开启 WebRTC,并进入模型界面。
3.3 结束图传
关闭浏览器页面即可结束电脑端观看。如需关闭设备图传,在 HUSKYLENS 2 上点击实时图传图标,关闭 WebRTC 开关并确认。
4. 其他实现
以下方法都使用第 2 节中准备好的设备 IP,无需重新按有线、无线分别操作。
| 实现方式 | 设备需开启的协议 | 用途 |
|---|---|---|
| Python 接收 WebRTC | WebRTC | 在 Python 中获取和处理图像 |
| Mind+ | WebRTC | 按照 Mind+ 教程使用实时画面 |
| VLC 播放 RTSP | RTSP | 使用播放器查看画面 |
| Python 接收 RTSP | RTSP | 使用 OpenCV 读取和处理图像 |
4.1 WebRTC 实时图传
4.1.1 Mind+ 实时图传
- 从Mind+ 下载页面下载并安装 Mind+ V2.x 系列。
- 完成第 2 节中的设备连接,按照 3.1 开启 WebRTC 并进入模型界面。
- 按照Mind+ 数据采集与采集设备指南中的 HUSKYLENS 2 说明进行操作。需要填写设备 IP 时,有线连接使用有线 IP,无线连接使用无线 IP。
结束使用后,如需关闭设备图传,请关闭 HUSKYLENS 2 的 WebRTC 开关。
4.1.2 Python实时图传
先按照 3.1 开启 WebRTC 并进入模型界面,再运行以下示例。
本教程使用 HUSKYLENS_WebRTC.py,通过设备上的 Janus 服务建立 WebRTC 连接,并使用 OpenCV 显示收到的图像。
第一步:准备 Python 环境并安装依赖
在电脑上下载并安装 Python。
Python 官方下载地址:点击查看
安装时,建议勾选 Add Python to PATH(将 Python 添加到系统环境变量),然后按照安装向导完成安装。
安装完成后,按下键盘上的 Win + R,输入 cmd,按下回车键打开命令提示符(CMD)。
在终端中输入以下命令:
python --version
如果终端显示 Python 版本号,例如 Python 3.x.x,则表示 Python 已安装成功。如果提示找不到 Python,请检查是否已正确安装并添加到系统环境变量。

在终端输入以下指令按下回车键执行:
python -m pip install aiohttp aiortc av opencv-python numpy

安装成功显示如下。

第二步:保存示例代码并修改 IP
复制以下代码,保存为 HUSKYLENS_WebRTC.py。将 JANUS_URL 中的 IP 改为第 2 节所选连接方式对应的设备 IP,保留端口 8088、路径 /janus 和流编号 99。
有线示例:http://192.168.88.1:8088/janus;无线示例:http://192.168.9.181:8088/janus(请替换为实际无线 IP)。
# aio.py — HUSKYLENS 2 Janus 实时视频流接收程序
# 功能:通过 Janus Streaming + WebRTC 接收视频流,
# 并使用 OpenCV 在电脑上实时显示画面。
import asyncio
import aiohttp
import json
import re
import cv2
import av
import traceback
import os
import sys
from aiortc import RTCPeerConnection, RTCSessionDescription, RTCRtpSender, MediaStreamTrack
# ==================== 1. 基本配置 ====================
# Janus 服务器地址,请根据 HUSKYLENS 2 的实际 IP 地址修改
JANUS_URL = "http://192.168.88.1:8088/janus"
# Janus Streaming 插件的视频流挂载点 ID
MOUNTPOINT_ID = 99
# ==================== 2. 工具函数 ====================
def txn():
"""生成随机事务 ID,用于区分不同的 Janus API 请求"""
import random
return str(random.randint(1, 999999999))
def sanitize_remove_rtx(sdp: str) -> str:
"""
处理 SDP 协商信息。
移除负载类型 97 对应的 RTX 信息,
并从指定的媒体格式列表中移除 97,
用于兼容当前视频流的协商配置。
"""
s = re.sub(r"\r?\na=rtpmap:97.*", "", sdp)
s = re.sub(r"\r?\na=fmtp:97.*", "", s)
s = s.replace("96 97", "96")
return s
def print_codecs():
"""打印本地 aiortc 支持的视频编解码器信息"""
try:
caps = RTCRtpSender.getCapabilities("video")
print("\n========== 本地视频编解码器 ==========")
for c in caps.codecs:
print(
"编码类型:", getattr(c, "mimeType", None),
"时钟频率:", getattr(c, "clockRate", None),
"SDP 参数:", getattr(c, "sdpFmtpLine", None),
"其他参数:", getattr(c, "parameters", None)
)
except Exception as e:
print("读取本地编解码器信息失败:", e)
# ==================== 3. 视频轨道 ====================
class BlackFrameTrack(MediaStreamTrack):
"""
创建一个黑色视频轨道。
默认分辨率:320 × 240
默认帧率:5 FPS
该类作为备用视频轨道保留,
当前主程序没有主动使用它。
"""
kind = "video"
def __init__(self, width=320, height=240, fps=5):
super().__init__()
import numpy as np
# 创建全黑图像
self._frame = np.zeros(
(height, width, 3),
dtype="uint8"
)
# 计算每帧的时间间隔
self._period = 1.0 / fps
async def recv(self):
"""生成并返回一帧黑色视频画面"""
frame = av.VideoFrame.from_ndarray(
self._frame,
format="bgr24"
)
await asyncio.sleep(self._period)
return frame
# ==================== 4. 连接保活 ====================
async def rtcp_keepalive(pc):
"""
尝试定时发送 RTCP 接收报告(RR)。
每隔 2 秒检查一次视频接收器。
注意:send_rtcp_rr() 并非所有 aiortc 版本
都支持的公开接口,实际是否发送取决于版本。
"""
while True:
await asyncio.sleep(2)
try:
for t in pc.getTransceivers():
if t.receiver:
try:
await t.receiver.send_rtcp_rr()
except Exception:
pass
except Exception:
pass
async def janus_keepalive(http, sid):
"""
定时向 Janus 服务器发送保活请求。
每隔 5 秒发送一次 keepalive,
避免 Janus 会话因长时间无请求而超时。
"""
while True:
await asyncio.sleep(5)
try:
await janus_post(
http,
f"{JANUS_URL}/{sid}",
{
"janus": "keepalive",
"transaction": txn()
}
)
print("已发送 Janus 保活请求")
except Exception as e:
print("Janus 保活请求失败:", e)
# ==================== 5. 视频接收与显示 ====================
async def video_consumer(track):
"""
接收 WebRTC 视频轨道中的画面。
将接收到的视频帧转换为 OpenCV 图像,
并在电脑上实时显示。
在视频窗口中按 Q 键退出视频接收循环。
"""
print("视频接收任务已启动")
try:
while True:
# 接收一帧视频
f = await track.recv()
# 转换为 OpenCV 使用的 BGR 图像格式
img = f.to_ndarray(format="bgr24")
# 显示视频画面
cv2.imshow("Janus Stream", img)
# 检测键盘输入,按 Q 退出当前视频循环
if cv2.waitKey(1) & 0xFF == ord("q"):
break
except Exception as e:
print("视频接收结束:", e)
# ==================== 6. Janus HTTP 通信 ====================
async def janus_post(session, url, data):
"""
向 Janus 服务器发送 HTTP POST 请求。
参数:
session:aiohttp 会话
url:请求地址
data:请求数据
返回:
Janus 服务器返回的 JSON 数据
"""
async with session.post(
url,
data=json.dumps(data)
) as resp:
return await resp.json()
async def janus_get(session, url):
"""
向 Janus 服务器发送 HTTP GET 请求。
主要用于获取 Janus 返回的异步事件,
包括 WebRTC SDP Offer 等信息。
"""
async with session.get(url) as resp:
return await resp.json()
# ==================== 7. 程序自动重启 ====================
async def restart_program():
"""
检测到 WebRTC 连接断开时,尝试重新启动程序。
注意:该方式适用于从 .py 文件启动的程序。
如果通过 python - 或终端内联代码执行,
自动重启可能无法恢复原程序。
"""
print("检测到连接断开,准备重新启动程序...")
await asyncio.sleep(1)
os.execv(
sys.executable,
['python'] + sys.argv
)
# ==================== 8. 主程序 ====================
async def main():
# 创建异步 HTTP 客户端会话
async with aiohttp.ClientSession() as http:
# ---------- 步骤 1:创建 Janus 会话 ----------
print("正在连接 Janus 服务器...")
r = await janus_post(
http,
JANUS_URL,
{
"janus": "create",
"transaction": txn()
}
)
# 获取 Janus Session ID
sid = r["data"]["id"]
print("Janus 会话创建成功,Session ID:", sid)
# ---------- 步骤 2:加载 Streaming 插件 ----------
r = await janus_post(
http,
f"{JANUS_URL}/{sid}",
{
"janus": "attach",
"plugin": "janus.plugin.streaming",
"transaction": txn()
}
)
# 获取插件 Handle ID
handle = r["data"]["id"]
print("Streaming 插件连接成功")
print("Session:", sid, "Handle:", handle)
# ---------- 步骤 3:启动 Janus 会话保活 ----------
asyncio.create_task(
janus_keepalive(http, sid)
)
# ---------- 步骤 4:订阅指定视频流 ----------
await janus_post(
http,
f"{JANUS_URL}/{sid}/{handle}",
{
"janus": "message",
"body": {
"request": "watch",
"id": MOUNTPOINT_ID
},
"transaction": txn()
}
)
print("已发送视频流订阅请求")
print("视频流 ID:", MOUNTPOINT_ID)
# ---------- 步骤 5:等待 SDP Offer ----------
offer = None
print("正在等待服务器返回 SDP Offer...")
while offer is None:
# 获取 Janus 异步事件
evs = await janus_get(
http,
f"{JANUS_URL}/{sid}?rid=1&maxev=10"
)
# 兼容列表和事件对象两种返回结构
evlist = (
evs
if isinstance(evs, list)
else evs.get("events", [evs])
)
# 查找包含 SDP 信息的事件
for ev in evlist:
if "jsep" in ev:
offer = ev["jsep"]
break
await asyncio.sleep(0.05)
print("已收到 SDP Offer")
# ---------- 步骤 6:处理 SDP 信息 ----------
raw_sdp = offer["sdp"]
# 移除指定 RTX 信息
sdp1 = sanitize_remove_rtx(raw_sdp)
print("\n========== SDP Offer(处理后)==========")
print(sdp1[:800])
print("========================================\n")
# ---------- 步骤 7:创建 WebRTC 连接 ----------
pc = RTCPeerConnection()
print("WebRTC PeerConnection 已创建")
# 启动 RTCP 保活任务
asyncio.create_task(
rtcp_keepalive(pc)
)
# ---------- 步骤 8:监听视频轨道 ----------
@pc.on("track")
def on_track(track):
"""
当 WebRTC 收到新的媒体轨道时触发。
如果是视频轨道,则启动视频接收任务。
"""
print("收到媒体轨道:", track.kind)
if track.kind == "video":
asyncio.create_task(
video_consumer(track)
)
# ---------- 步骤 9:监听连接状态 ----------
@pc.on("iceconnectionstatechange")
def on_ice():
"""
监听 ICE 连接状态。
当连接关闭、失败或断开时,
尝试重新启动程序。
"""
print("ICE 连接状态:", pc.iceConnectionState)
if pc.iceConnectionState in (
"closed",
"failed",
"disconnected"
):
asyncio.create_task(
restart_program()
)
# ---------- 步骤 10:设置远程 SDP ----------
try:
print("正在设置远程 SDP...")
# 打印本地支持的视频编码格式
print_codecs()
# 设置 Janus 返回的远程 SDP Offer
await pc.setRemoteDescription(
RTCSessionDescription(
sdp1,
"offer"
)
)
print("远程 SDP 设置成功")
except Exception as e:
print("远程 SDP 设置失败:", e)
traceback.print_exc()
return
# ---------- 步骤 11:创建 SDP Answer ----------
print("正在生成 SDP Answer...")
answer = await pc.createAnswer()
await pc.setLocalDescription(answer)
print("本地 SDP Answer 生成成功")
# ---------- 步骤 12:发送 SDP Answer ----------
await janus_post(
http,
f"{JANUS_URL}/{sid}/{handle}",
{
"janus": "message",
"body": {
"request": "start"
},
"jsep": {
"type": "answer",
"sdp": pc.localDescription.sdp
},
"transaction": txn()
}
)
print("SDP Answer 已发送")
print("正在等待视频流...")
print("视频窗口打开后,按 Q 键退出视频显示")
print("在终端按 Ctrl+C 可停止程序")
# ---------- 步骤 13:保持程序运行 ----------
while True:
await asyncio.sleep(1)
# ==================== 9. 程序入口 ====================
if __name__ == "__main__":
# 启动 asyncio 事件循环并执行主程序
asyncio.run(main())
第三步:运行代码
在保存 HUSKYLENS_WebRTC.py 的文件夹中,点击资源管理器地址栏,输入 cmd 并按回车,打开终端。

在终端输入以下命令,按下回车执行:

python HUSKYLENS_WebRTC.py
程序会连接设备并进行 WebRTC 协商。成功收到视频后,会显示名为 Janus Stream 的画面窗口。
当前示例中,在视频窗口按 q 只会结束视频接收循环,主程序仍会继续运行。结束整个程序时,请回到运行程序的终端,按 Ctrl+C。
如需关闭设备图传,请同时关闭 HUSKYLENS 2 的 WebRTC 图传开关。
4.2 RTSP实时图传
4.2.1 VLC 应用实时图传
准备:开启 RTSP 图传
在 HUSKYLENS 2 中进入“实时图传”,打开 RTSP 开关并确认。返回主界面后打开一个模型,记录对应连接方式的设备 IP。
RTSP 地址格式为 rtsp://设备IP:8554/live:
| 当前连接方式 | RTSP 地址示例 |
|---|---|
| USB 有线 | rtsp://192.168.88.1:8554/live |
| WiFi 无线 | rtsp://192.168.9.181:8554/live(替换为实际无线 IP) |
第一步:安装 VLC
通过 VLC 官方下载页面下载并安装适用于电脑系统的版本。
第二步:打开网络串流
启动 VLC,在菜单中选择“媒体 → 打开网络串流”。
填写设备的 RTSP 地址。下面是有线示例;使用 WiFi 时,将 IP 替换为设备屏幕显示的无线 IP:
rtsp://192.168.88.1:8554/live
第三步:查看画面
点击播放,等待 VLC 显示实时画面。
第四步:结束图传
停止播放或关闭 VLC。如需关闭设备图传,请在 HUSKYLENS 2 上关闭 RTSP 图传开关。
4.2.2 Python实时图传
先按照 4.2.1 的准备步骤开启 RTSP 并进入模型界面。
第一步:安装依赖
如果尚未安装 Python,请参考 4.1 的 Python 环境准备步骤。打开终端,执行:
python -m pip install opencv-python
第二步:保存代码并修改 IP
复制以下代码,保存为 HUSKYLENS_RTSP.py。将 DEVICE_IP 改为设备当前的 IP:有线填写有线 IP,无线填写无线 IP。
import cv2
DEVICE_IP = "192.168.88.1" # 无线连接时改为设备实际的无线 IP
rtsp_url = f"rtsp://{DEVICE_IP}:8554/live"
cap = cv2.VideoCapture(rtsp_url)
try:
if not cap.isOpened():
raise RuntimeError("无法打开视频流,请检查设备 IP、网络连接和 RTSP 开关。")
while True:
ret, frame = cap.read()
if not ret:
print("未能读取画面,请检查设备及网络连接。")
break
# 可在这里添加自己的图像处理代码
cv2.imshow("RTSP Live", frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
finally:
cap.release()
cv2.destroyAllWindows()
第三步:运行程序
在代码所在文件夹打开终端,执行:
python HUSKYLENS_RTSP.py
成功读取视频后,会显示 RTSP Live 画面窗口。代码中的 frame 是本次读取到的图像,可以用于后续处理。
选中视频窗口后按 q 退出,或在终端按 Ctrl+C 停止程序。如需关闭设备图传,请同时关闭 HUSKYLENS 2 的 RTSP 开关。